// Copyright (C) Calum Grant 2008

#include "cppscript"
#include "dynamic/extensions.hpp"

using internal::nonroot_var;


namespace dynamic
{
	namespace types
	{
	/// Implements a dispatcher container, returned by the \ref dispatcher() function.
	/** \ingroup  impl */
	class dispatcher_impl : public shared_var_impl
	{
		nonroot_var m_object;

	public:
		dispatcher_impl(const var & object) : 
			m_object(object)
		{
		}

		void mark_children(gc::garbage_collector & gc)
		{
			m_object.ref().impl().mark_reachable(gc);
		}

		var_cmp_index comparison_index() 
		{ 
			return cmp_dispatcher; 
		}

		void pickle(pickler & p)
		{
			p.write_object_type(cmp_dispatcher);
			p.write_object(m_object.ref());
		}

		void unpickle(unpickler & p)
		{
			m_object = p.read_object();
		}

		var get_member(const var & member)
		{
			return m_object.ref()["get_member"](member);
		}

		void set_member(const var & member, const var & value)
		{
			m_object.ref()["set_member"](member, value);
		}

		std::string class_name() 
		{ 
			return m_object.ref()["class_name"]().as_string(); 
		}

		var call() 
		{ 
			return m_object.ref()["call"](); 
		}

		var call(const var & a0) 
		{ 
			return m_object.ref()["call"](a0); 
		}

		var call(const var & a0, const var & a1) 
		{ 
			return m_object.ref()["call"](a0,a1); 
		}
		
		var call(const var & a0, const var & a1,const var & a2) 
		{ 
			return m_object.ref()["call"](a0,a1,a2); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3,const var &a4) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3,a4); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3,const var &a4,const var&a5) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3,a4,a5); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3,const var &a4,const var&a5,const var &a6) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3,a4,a5,a6); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3,const var &a4,const var&a5,const var &a6,const var &a7) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3,a4,a5,a6,a7); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3,const var &a4,const var&a5,const var &a6,const var &a7,const var &a8) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3,a4,a5,a6,a7,a8); 
		}
		
		var call(const var & a0, const var & a1,const var & a2,const var & a3,const var &a4,const var&a5,const var &a6,const var &a7,const var &a8,const var &a9) 
		{ 
			return m_object.ref()["call"](a0,a1,a2,a3,a4,a5,a6,a7,a8,a9); 
		}

		int max_args() 
		{ 
			return m_object.ref()["call"].max_args(); 
		}

		void output(ostream & os)
		{
			os << m_object.ref()["as_string"]();
		}

		void output(wostream & os)
		{
			os << m_object.ref()["as_string"]();
		}

		int as_int() 
		{ 
			return m_object.ref()["as_int"]().as_int(); 
		}

		double as_double() 
		{ 
			return m_object.ref()["as_double"]().as_double(); 
		}

		bool as_bool() 
		{ 
			return m_object.ref()["as_bool"]().as_bool(); 
		}

		int size() 
		{ 
			return m_object.ref()["size"]().as_int(); 
		}

		void resize(std::size_t new_size) 
		{ 
			m_object.ref()["resize"](int(new_size)); 
		}

		bool empty() 
		{ 
			return m_object.ref()["empty"](); 
		}

		var enumerator() 
		{ 
			return m_object.ref()["enumerator"](); 
		}

		var reverse_enumerator() 
		{ 
			return m_object.ref()["reverse_enumerator"](); 
		}

		var keys() 
		{ 
			return m_object.ref()["keys"](); 
		}

		var values() 
		{ 
			return m_object.ref()["values"](); 
		}

		void insert(const var & i) 
		{ 
			m_object.ref()["insert"](i); 
		}

		void reserve(std::size_t i) 
		{ 
			m_object.ref()["reserve"](int(i)); 
		}

		std::size_t capacity() 
		{ 
			return m_object.ref()["capacity"]().as_int(); 
		}

		void push_back(const var & v) 
		{ 
			m_object.ref()["push_back"](v); 
		}

		void push_front(const var & v) 
		{ 
			m_object.ref()["push_front"](v); 
		}

		var pop_back() 
		{ 
			return m_object.ref()["pop_back"]();
		}

		var pop_front() 
		{ 
			return m_object.ref()["pop_front"](); 
		}

		var back() 
		{ 
			return m_object.ref()["back"](); 
		}

		var front() 
		{ 
			return m_object.ref()["front"](); 
		}

		void clear() 
		{ 
			m_object.ref()["clear"]();
		}

		bool contains(const var & a) 
		{ 
			return m_object.ref()["contains"](a); 
		}

		void erase(const var & a) 
		{
			m_object.ref()["erase"](a);
		}

		var clone() 
		{ 
			return m_object.ref()["clone"](); 
		}

		var key() 
		{ 
			return m_object.ref()["key"](); 
		}

		var value() 
		{ 
			return m_object.ref()["value"](); 
		}

		var deref() 
		{ 
			return m_object.ref()["deref"](); 
		}

		void op_inc() 
		{ 
			m_object.ref()["++"](); 
		}

		void op_dec() 
		{ 
			m_object.ref()["--"](); 
		}

		var op_add(const var & a) 
		{ 
			return m_object.ref()["+"](a); 
		}

		var op_sub(const var & a) 
		{ 
			return m_object.ref()["-"](a);
		}

		var op_mul(const var & a)
		{ 
			return m_object.ref()["*"](a); 
		}

		var op_div(const var & a) 
		{ 
			return m_object.ref()["/"](a); 
		}

		var op_mod(const var & a) 
		{ 
			return m_object.ref()["%"](a); 
		}

		var op_neg()
		{
			return m_object.ref()["neg"]();
		}

		var op_lshift(const var & a) 
		{
			return m_object.ref()["<<"](a);
		}

		var op_rshift(const var & a) 
		{
			return m_object.ref()[">>"](a);
		}

		var op_and(const var & a) 
		{
			return m_object.ref()["&"](a);
		}

		var op_or(const var & a) 
		{
			return m_object.ref()["|"](a);
		}

		var op_xor(const var & a) 
		{
			return m_object.ref()["^"](a);
		}

		var op_inv() 
		{
			return m_object.ref()["~"]();
		}

		void assign_add(const var & a)
		{
			m_object.ref()["+="](a);
		}

		void assign_sub(const var & a)
		{ 
			m_object.ref()["-="](a); 
		}

		void assign_mul(const var & a)
		{
			m_object.ref()["*="](a);
		}

		void assign_div(const var & a)
		{
			m_object.ref()["/="](a); 
		}

		void assign_mod(const var & a)
		{
			m_object.ref()["%="](a); 
		}

		void assign_lshift(const var & a)
		{
			m_object.ref()["<<="](a); 
		}

		void assign_rshift(const var & a)
		{
			m_object.ref()[">>="](a); 
		}

		void assign_and(const var & a)
		{ 
			m_object.ref()["&="](a); 
		}

		void assign_or(const var & a)
		{
			m_object.ref()["|="](a); 
		}

		void assign_xor(const var & a)
		{
			m_object.ref()["^="](a); 
		}
	};
	}
}


var dynamic::dispatcher(const var & object)
{
	return new types::dispatcher_impl(object);
}
